#!/bin/bash

set -e

# Basic paths
TOP=$(pwd)
BOARD_DIR=${TOP}/device/board/3516cv610
SOC_DIR=${TOP}/device/soc/hisilicon/3516cv610
TOOL_DIR=/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc

# Version info
GIT_VERSION=$(git describe --tags --always)
BUILD_TIME=$(date +%Y%m%d%H%M)
VERSION="V1.0.0.${BUILD_TIME}.${GIT_VERSION}"
PRODUCT_NAME="ipc100"

# Output paths
FIRMWARE=${TOP}/out/image
BUILD_WORKSPACE=${TOP}/out/build_workspace
WS_IMG_DIR=${BUILD_WORKSPACE}/images
BURN_DIR=${FIRMWARE}/burn
UPGRADE_DIR=${FIRMWARE}/upgrade

# Rootfs structure (moved to build workspace)
ROOTFS=${BUILD_WORKSPACE}/rootfs
ROOTFS_DIRS=(
    "${ROOTFS}/home"
    "${ROOTFS}/mnt"
    "${ROOTFS}/mnt/assets"
    "${ROOTFS}/mnt/config"
    "${ROOTFS}/mnt/log"
    "${ROOTFS}/mnt/data"
    "${ROOTFS}/mnt/udisk"
)

# Assets paths (moved to build workspace)
ASSETS_ROOT=${BUILD_WORKSPACE}/assets

# Print info message with color
function mk_info() {
    echo -e "\033[47;30m[endless]: $*\033[0m"
}

# Initialize build environment
function init_env() {
    mk_info "Initializing build environment..."

    # Clean up previous builds
    rm -rf ${FIRMWARE}
    rm -rf ${BUILD_WORKSPACE}

    # Create final product directories
    mkdir -p ${FIRMWARE} ${BURN_DIR} ${UPGRADE_DIR}

    # Create build workspace directories
    mkdir -p ${BUILD_WORKSPACE} ${ASSETS_ROOT} ${WS_IMG_DIR}

    # Create rootfs directories in build workspace
    for dir in "${ROOTFS_DIRS[@]}"; do
        mkdir -p "$dir"
    done

    mk_info "Created directories:"
    mk_info "  - Final products: ${FIRMWARE}"
    mk_info "  - Build workspace: ${BUILD_WORKSPACE}"
}

# Clean up unnecessary files from rootfs
function cleanup_rootfs() {
    mk_info "Cleaning up unnecessary files from rootfs..."

    # 删除网络配置
    rm -rf ${ROOTFS}/etc/init.d/S01syslogd
    rm -rf ${ROOTFS}/etc/init.d/S02klogd
    #rm -rf ${ROOTFS}/etc/init.d/S02sysctl
    # rm -rf ${ROOTFS}/etc/init.d/S40network
    rm -rf ${ROOTFS}/etc/init.d/S50telnet
    rm -rf ${ROOTFS}/etc/init.d/S80network

    # 移除现场不需要的命令行工具（体积不大，但能减少噪音）
    for bin in ffmpeg sqlite3 openssl pcre2test pcre2grep gio \
               gst-launch-1.0 gst-inspect-1.0 gst-stats-1.0 gst-typefind-1.0 \
               gdbus gsettings gapplication gresource xmllint xmlcatalog; do
        rm -f "${ROOTFS}/usr/bin/${bin}"
    done

    # 可选：删除 ALSA 工具（若仅在生产调试阶段使用）
    if [ -n "${DROP_ALSA_TOOLS}" ]; then
        for bin in aplay arecord amixer alsamixer aserver; do
            rm -f "${ROOTFS}/usr/bin/${bin}"
        done
    fi

    # 3) 精简时区数据，只保留东八区 (Asia/Shanghai)
    if [ -d "${ROOTFS}/usr/share/zoneinfo" ]; then
        local tz_dir="${ROOTFS}/usr/share/zoneinfo"
        local tz_tmp="${tz_dir}_tmp"
        if [ -f "${tz_dir}/Asia/Shanghai" ]; then
            mkdir -p "${tz_tmp}/Asia"
            cp "${tz_dir}/Asia/Shanghai" "${tz_tmp}/Asia/"
            rm -rf "${tz_dir}"
            mv "${tz_tmp}" "${tz_dir}"
        else
            rm -rf "${tz_dir}"
        fi
    fi

    # 4) 精简 locale，仅保留 C/en_US/zh_CN（若存在）
    if [ -z "${KEEP_LOCALE_FULL}" ] && [ -d "${ROOTFS}/usr/share/locale" ]; then
        find "${ROOTFS}/usr/share/locale" -mindepth 1 -maxdepth 1 -type d \
            ! -name "C" ! -name "C.UTF-8" ! -name "POSIX" \
            ! -name "en_US" ! -name "en_US.*" \
            ! -name "zh_CN" ! -name "zh_CN.*" \
            -exec rm -rf {} + 2>/dev/null || true
    fi

    # 可选：删除 ALSA/terminfo 数据（如无需本地调音与交互终端）
    if [ -n "${DROP_ALSA_DATA}" ] || [ -n "${AGGRESSIVE_SHRINK}" ]; then
        rm -rf ${ROOTFS}/usr/share/alsa 2>/dev/null || true
        mk_info "Removed ALSA share data"
    fi
    if [ -n "${DROP_TERMINFO}" ] || [ -n "${AGGRESSIVE_SHRINK}" ]; then
        rm -rf ${ROOTFS}/usr/share/terminfo 2>/dev/null || true
        mk_info "Removed terminfo data"
    fi

    # 可选：移除 ntfs-3g（若设备不需要 U 盘 NTFS 支持）
    if [ -n "${DROP_NTFS}" ] || [ -n "${AGGRESSIVE_SHRINK}" ]; then
        rm -f ${ROOTFS}/usr/bin/ntfs-3g* 2>/dev/null || true
        rm -f ${ROOTFS}/usr/bin/lowntfs-3g 2>/dev/null || true
        rm -rf ${ROOTFS}/usr/lib/ntfs-3g 2>/dev/null || true
        rm -f ${ROOTFS}/usr/lib/libntfs-3g.so* 2>/dev/null || true
        mk_info "Removed ntfs-3g (DROP_NTFS)"
    fi

    mk_info "Rootfs cleanup completed."
}

# Pack rootfs
function pack_rootfs() {
    mk_info "=============================================="
    mk_info "Packing rootfs..."
    mk_info "=============================================="
    
    cd ${BOARD_DIR}/rootfs
    tar -xvf rootfs.tar.gz -C ${ROOTFS}
    cd ${ROOTFS}
    
    # Copy overlay files
    cp ${BOARD_DIR}/rootfs/overlay/* ${ROOTFS}/ -rf
    cp ${SOC_DIR}/lib/*.so ${ROOTFS}/usr/lib/ -rf

    # Copy endless binaries to usr/bin
    if [ -f ${TOP}/out/bin/endless ]; then
        cp ${TOP}/out/bin/endless ${ROOTFS}/usr/bin/ -rf
        cp ${TOP}/out/bin/elsh ${ROOTFS}/usr/bin/ -rf
        mk_info "Copied endless binaries to usr/bin"
    fi
    
    # Copy kernel modules to usr/lib/modules
    if [ -d ${SOC_DIR}/ko ]; then
        mkdir -p ${ROOTFS}/usr/lib/modules
        cp ${SOC_DIR}/ko/* ${ROOTFS}/usr/lib/modules/ -rf
        mk_info "Copied kernel modules to usr/lib/modules"
    fi

    # 清理与瘦身（放在最后，确保拷贝完成后再处理）
    cleanup_rootfs
}

# Pack assets files
function pack_assets() {
    mk_info "=============================================="
    mk_info "Packing assets..."
    mk_info "=============================================="
    
    # Create assets root directory
    mkdir -p ${ASSETS_ROOT}
    
    cp ${BOARD_DIR}/assets/* ${ASSETS_ROOT}/ -rf
    
    # Prefer prebuilt web in out/web; fallback to foundation/web_page/dist
    if [ -d ${TOP}/out/web ]; then
        cp -rf ${TOP}/out/web ${ASSETS_ROOT}/web
        mk_info "Copied web UI from out/web"
    elif [ -d ${TOP}/foundation/web_page/dist ]; then
        mkdir -p ${TOP}/out/web
        cp -rf ${TOP}/foundation/web_page/dist/* ${TOP}/out/web/
        cp -rf ${TOP}/out/web ${ASSETS_ROOT}/web
        mk_info "Copied web UI from foundation/web_page/dist"
    else
        mk_info "WARNING: No web UI found (out/web or foundation/web_page/dist)"
    fi
    
    mk_info "Assets packing completed."
}

# Generate rootfs image
function generate_rootfs_image() {
    mk_info "=============================================="
    mk_info "Generating rootfs SquashFS image and UBI static volume..."
    mk_info "=============================================="
    
    pushd ${ROOTFS}
    ${TOOL_DIR}/tools/install_dynamic_basic_library.sh ${TOOL_DIR} ${ROOTFS} a7_softfp_neon-vfpv4
    popd

    local SQUASHFS_COMP=${SQUASHFS_COMP:-gzip}
    local SQUASHFS_BLOCK=${SQUASHFS_BLOCK:-128K}
    mksquashfs ${ROOTFS} ${WS_IMG_DIR}/rootfs.squashfs -comp ${SQUASHFS_COMP} -b ${SQUASHFS_BLOCK} -noappend -no-xattrs

    local PAGE_SIZE="2048"
    local BLOCK_SIZE="131072"
    local PEB_SIZE="${BLOCK_SIZE}"

    cp ${BOARD_DIR}/uboot/rootfs_ubi.cfg ${WS_IMG_DIR}/

    mk_info "Creating rootfs UBI image with static SquashFS volume..."
    mk_info "  NAND Page Size: ${PAGE_SIZE} bytes"
    mk_info "  NAND Block Size: ${BLOCK_SIZE} bytes (128K)"
    mk_info "  Volume Type: static"
    mk_info "  Volume Name: rootfs"

    # Run ubinize in WS_IMG_DIR so relative image path in cfg resolves
    pushd ${WS_IMG_DIR} >/dev/null
    ubinize -o rootfs.ubi -m ${PAGE_SIZE} -p ${PEB_SIZE} -s ${PAGE_SIZE} rootfs_ubi.cfg
    local UBI_RET=$?
    popd >/dev/null

    if [ ${UBI_RET} -eq 0 ]; then
        mk_info "Rootfs UBI image created successfully: rootfs.ubi"
        mk_info "  SquashFS image: ${WS_IMG_DIR}/rootfs.squashfs"
        mk_info "  UBI static volume: ${WS_IMG_DIR}/rootfs.ubi"
        # Place final image in burn directory
        cp ${WS_IMG_DIR}/rootfs.ubi ${BURN_DIR}/rootfs.img
    else
        mk_info "ERROR: Failed to create rootfs UBI image!"
        exit 1
    fi
}

# Generate assets image
function generate_assets_image() {
    mk_info "=============================================="
    mk_info "Generating assets UBI image with static SquashFS volume..."
    mk_info "=============================================="

    # First create SquashFS image into workspace
    local SQUASHFS_COMP=${SQUASHFS_COMP:-gzip}
    local SQUASHFS_BLOCK=${SQUASHFS_BLOCK:-128K}
    mksquashfs ${ASSETS_ROOT} ${WS_IMG_DIR}/assets.squashfs -comp ${SQUASHFS_COMP} -b ${SQUASHFS_BLOCK} -noappend -no-xattrs

    # Get NAND parameters from board configuration
    local PAGE_SIZE="2048"    # 2K page size for 3516cv610 NAND
    local BLOCK_SIZE="131072"  # 128K block size
    local PEB_SIZE="${BLOCK_SIZE}"

    # Copy UBI config to workspace
    cp ${BOARD_DIR}/uboot/assets_ubi.cfg ${WS_IMG_DIR}/

    mk_info "Creating UBI image with static volume..."
    mk_info "  NAND Page Size: ${PAGE_SIZE} bytes"
    mk_info "  NAND Block Size: ${BLOCK_SIZE} bytes (128K)"
    mk_info "  Volume Type: static"
    mk_info "  Volume Name: assets"

    # Generate UBI image into workspace using ubinize
    # -o: output file
    # -m: min I/O size (page size)
    # -p: physical erase block size (block size)
    # -s: sub-page size (for 2K pages, typically 512 or 2048)
    pushd ${WS_IMG_DIR} >/dev/null
    ubinize -o assets.ubi -m ${PAGE_SIZE} -p ${PEB_SIZE} -s ${PAGE_SIZE} assets_ubi.cfg
    local UBI_RET=$?
    popd >/dev/null

    if [ ${UBI_RET} -eq 0 ]; then
        mk_info "UBI image created successfully: ${WS_IMG_DIR}/assets.ubi"
        # Place final image in burn directory
        cp ${WS_IMG_DIR}/assets.ubi ${BURN_DIR}/assets.img
    else
        mk_info "ERROR: Failed to create UBI image!"
        exit 1
    fi

}

# Generate final image
function generate_image() {
    mk_info "=============================================="
    mk_info "Generating final image..."
    mk_info "=============================================="
    
    # Copy boot and kernel files directly to burn directory
    if [ -f ${BOARD_DIR}/uboot/boot_image.bin ]; then
        cp ${BOARD_DIR}/uboot/boot_image.bin ${BURN_DIR}/uboot.img
    fi
    if [ -f ${BOARD_DIR}/uboot/nand_env.bin ]; then
        cp ${BOARD_DIR}/uboot/nand_env.bin ${BURN_DIR}/env.img
    fi
    if [ -f ${BOARD_DIR}/kernel/uImage ]; then
        cp ${BOARD_DIR}/kernel/uImage ${BURN_DIR}/kernel.img
    fi
    
    # Generate filesystem images
    generate_rootfs_image
    generate_assets_image
    
    # Board burn table into burn directory
    if [ -f ${BOARD_DIR}/uboot/nand_burn_table.xml ]; then
        cp ${BOARD_DIR}/uboot/nand_burn_table.xml ${BURN_DIR}/
    fi
}

# Generate human-readable description (JSON) for the upgrade package
function generate_description() {
    mk_info "Generating upgrade description (description.json)..."

    # Refresh version info
    GIT_VERSION=$(git describe --tags --always)
    BUILD_TIME=$(date +%Y%m%d%H%M)
    VERSION="V1.0.0.${BUILD_TIME}.${GIT_VERSION}"

    cat > ${UPGRADE_DIR}/description.json << EOF
{
  "swdesc_version": "1.0",
  "software": {
    "version": "${VERSION}",
    "stable": {
      "slota": {
        "images": [
          { "filename": "kernel.img", "type": "flash", "device": "mtd2" },
          { "filename": "rootfs.img", "type": "flash", "device": "mtd3" },
          { "filename": "assets.img",  "type": "flash", "device": "mtd6" }
        ]
      },
      "slotb": {
        "images": [
          { "filename": "kernel.img", "type": "flash", "device": "mtd4" },
          { "filename": "rootfs.img", "type": "flash", "device": "mtd5" },
          { "filename": "assets.img",  "type": "flash", "device": "mtd6" }
        ]
      }
    }
  }
}
EOF
}

# Generate upgrade package (.upg) for self-developed upgrader
function generate_upgrade_package() {
    mk_info "=============================================="
    mk_info "Generating upgrade package (.upg, CPIO newc)..."
    mk_info "=============================================="

    mkdir -p ${UPGRADE_DIR}

    local UPGRADE_TEMP_DIR=${UPGRADE_DIR}/temp_upgrade
    rm -rf ${UPGRADE_TEMP_DIR}
    mkdir -p ${UPGRADE_TEMP_DIR}

    local MISSING_FILES=0

    if [ -f ${BURN_DIR}/kernel.img ]; then
        cp ${BURN_DIR}/kernel.img ${UPGRADE_TEMP_DIR}/kernel.img
        mk_info "Copied kernel.img"
    else
        mk_info "ERROR: kernel.img not found in ${BURN_DIR}/"; MISSING_FILES=1
    fi

    if [ -f ${BURN_DIR}/rootfs.img ]; then
        cp ${BURN_DIR}/rootfs.img ${UPGRADE_TEMP_DIR}/rootfs.img
        mk_info "Copied rootfs.img"
    else
        mk_info "ERROR: rootfs.img not found in ${BURN_DIR}/"; MISSING_FILES=1
    fi

    if [ -f ${BURN_DIR}/assets.img ]; then
        cp ${BURN_DIR}/assets.img ${UPGRADE_TEMP_DIR}/assets.img
        mk_info "Copied assets.img"
    else
        mk_info "ERROR: assets.img not found in ${BURN_DIR}/"; MISSING_FILES=1
    fi

    if [ ${MISSING_FILES} -ne 0 ]; then
        mk_info "ERROR: Missing required image files, aborting upgrade package generation"
        rm -rf ${UPGRADE_TEMP_DIR}
        return 1
    fi

    # Version
    GIT_VERSION=$(git describe --tags --always)
    BUILD_TIME=$(date +%Y%m%d%H%M)
    CONTAINER_VER="V1.0.0.${BUILD_TIME}.${GIT_VERSION}"

    # Generate description file and include it
    generate_description
    cp ${UPGRADE_DIR}/description.json ${UPGRADE_TEMP_DIR}/

    pushd ${UPGRADE_TEMP_DIR} >/dev/null
    local PACKAGE_NAME=${PRODUCT_NAME}_${CONTAINER_VER}.upg
    mk_info "Creating CPIO archive (newc) as ${PACKAGE_NAME}"
    (for f in description.json kernel.img rootfs.img assets.img; do echo ${f}; done) | cpio -ov -H newc > ${UPGRADE_DIR}/${PACKAGE_NAME}
    popd >/dev/null

    rm -rf ${UPGRADE_TEMP_DIR}

    mk_info "Generated upgrade package: ${UPGRADE_DIR}/${PRODUCT_NAME}_${CONTAINER_VER}.upg"
    # Remove standalone description.json; it is embedded in .upg
    rm -f ${UPGRADE_DIR}/description.json || true
}

# Generate unified distribution package (burn + upgrade combined)
function generate_distribution_package() {
    mk_info "=============================================="
    mk_info "Generating unified distribution package..."
    mk_info "=============================================="

    local DIST_PACKAGE_NAME="${PRODUCT_NAME}_distribution_${VERSION}.tar.gz"
    local DIST_PACKAGE_PATH="${FIRMWARE}/${DIST_PACKAGE_NAME}"
    local DIST_TEMP_DIR="${FIRMWARE}/temp_distribution"

    # Create temporary directory for distribution package
    rm -rf ${DIST_TEMP_DIR}
    mkdir -p ${DIST_TEMP_DIR}

    # Create distribution info file
    cat > ${DIST_TEMP_DIR}/distribution_info.txt << EOF
===============================================
Open IPC 3516CV610 Distribution Package
===============================================

Product Information:
  Product Name: ${PRODUCT_NAME}
  Version: ${VERSION}
  Build Time: ${BUILD_TIME}
  Git Version: ${GIT_VERSION}
  Platform: 3516CV610

Package Contents:
  1. Burn Directory (burn/):
     - For initial device flashing in production
     - Contains: uboot.img, kernel.img, rootfs.img, assets.img, env.img
     - Use individual .img files with flashing tools

  2. Upgrade Directory (upgrade/):
     - For over-the-air firmware updates
     - Contains: upgrade package (${PRODUCT_NAME}_${VERSION}.upg)
     - Deploy to update server for OTA updates

Usage Instructions:
  Production Flashing:
    1. Extract burn/ directory
    2. Use individual .img files with your flashing tool
    3. Follow the sequence: uboot → env → kernel → rootfs → assets

  OTA Updates:
    1. Extract upgrade/ directory
    2. Deploy the .upg file to your update server
    3. Use device's self-developed upgrader to stream the .upg to device

===============================================
Generated: $(date '+%Y-%m-%d %H:%M:%S')
===============================================
EOF

    # Copy burn and upgrade directories to temp directory
    if [ -d "${BURN_DIR}" ]; then
        cp -r "${BURN_DIR}" ${DIST_TEMP_DIR}/
        mk_info "Added burn directory to distribution"
    else
        mk_info "WARNING: Burn directory not found, skipping"
    fi

    if [ -d "${UPGRADE_DIR}" ]; then
        cp -r "${UPGRADE_DIR}" ${DIST_TEMP_DIR}/
        mk_info "Added upgrade directory to distribution"
    else
        mk_info "WARNING: Upgrade directory not found, skipping"
    fi

    # Create the unified distribution package
    pushd ${FIRMWARE}
    tar -czf ${DIST_PACKAGE_NAME} \
        -C temp_distribution \
        .
    popd

    # Clean up temporary directory
    rm -rf ${DIST_TEMP_DIR}

    if [ -f "${DIST_PACKAGE_PATH}" ]; then
        local DIST_SIZE=$(du -h "${DIST_PACKAGE_PATH}" | cut -f1)
        mk_info "Generated distribution package: ${DIST_PACKAGE_NAME} (${DIST_SIZE})"
        mk_info "Distribution package contents:"
        tar -tzf "${DIST_PACKAGE_PATH}" | head -20 | sed 's/^/  - /'
        if [ $(tar -tzf "${DIST_PACKAGE_PATH}" | wc -l) -gt 20 ]; then
            mk_info "  ... and $(( $(tar -tzf "${DIST_PACKAGE_PATH}" | wc -l) - 20 )) more files"
        fi
    else
        mk_info "ERROR: Failed to create distribution package"
        return 1
    fi
}


# Main process
function main() {
    init_env
    pack_rootfs
    pack_assets
    generate_image

    # Generate self-defined upgrade package
    generate_upgrade_package

    # Generate unified distribution package (burn + upgrade combined)
    generate_distribution_package

    mk_info "=============================================="
    mk_info "Build Success !!! ^_^"
    mk_info "=============================================="
    mk_info "Directory Structure:"
    mk_info "  📦 Final Products (${FIRMWARE}):"
    mk_info "     ├── burn/                              # Flash images"
    mk_info "     ├── upgrade/                           # OTA packages"
    mk_info "     └── ${PRODUCT_NAME}_distribution_${VERSION}.tar.gz  # Unified package"
    mk_info "  🔧 Build Workspace (${BUILD_WORKSPACE}):"
    mk_info "     ├── rootfs/                            # Build artifacts"
    mk_info "     └── assets/                            # Build artifacts"
    mk_info "=============================================="
    mk_info "🎯 Distribution: Use ${PRODUCT_NAME}_distribution_${VERSION}.tar.gz"
    mk_info "   This contains both burn and upgrade directories!"
    mk_info "=============================================="
}

main
